// rdfeed.cpp
//
// An RSS Feed Generator for Rivendell.
//
//   (C) Copyright 2002-2007 Fred Gleason <fredg@paravelsystems.com>
//
//      $Id: rdfeed.cpp,v 1.9 2007/10/30 17:10:40 fredg Exp $
//
//   This program is free software; you can redistribute it and/or modify
//   it under the terms of the GNU General Public License version 2 as
//   published by the Free Software Foundation.
//
//   This program is distributed in the hope that it will be useful,
//   but WITHOUT ANY WARRANTY; without even the implied warranty of
//   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//   GNU General Public License for more details.
//
//   You should have received a copy of the GNU General Public
//   License along with this program; if not, write to the Free Software
//   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <ctype.h>

#include <qapplication.h>
#include <qdatetime.h>

#include <rdconf.h>
#include <rdconfig.h>
#include <rdpodcast.h>
#include <rddb.h>
#include <rdfeed.h>
#include <rdweb.h>


MainObject::MainObject(QObject *parent,const char *name)
  :QObject(parent,name)
{
  QString sql;
  RDSqlQuery *q;
  RDSqlQuery *q1;

  //
  // Validate Feed Key Name
  //
  if(getenv("QUERY_STRING")==NULL) {
    printf("Content-type: text/html\n\n");
    printf("rdfeed: missing feed key name\n");
    exit(0);
  }
  if(strlen(getenv("QUERY_STRING"))>8) {
    printf("Content-type: text/html\n\n");
    printf("rdfeed: invalid feed key name\n");
    exit(0);
  }

  //
  // Read Configuration
  //
  RDConfig *config=new RDConfig();
  config->load();

  //
  // Open Database
  //
  QSqlDatabase *db=QSqlDatabase::addDatabase(config->mysqlDriver());
  if(!db) {
    printf("Content-type: text/html\n\n");
    printf("rdfeed: unable to initialize connection to database\n");
    exit(0);
  }
  db->setDatabaseName(config->mysqlDbname());
  db->setUserName(config->mysqlUsername());
  db->setPassword(config->mysqlPassword());
  db->setHostName(config->mysqlHostname());
  if(!db->open()) {
    printf("Content-type: text/html\n\n");
    printf("rdfeed: unable to connect to database\n");
    db->removeDatabase(config->mysqlDbname());
    exit(0);
  }

  sql=QString().sprintf("select CHANNEL_TITLE,CHANNEL_DESCRIPTION,\
                         CHANNEL_CATEGORY,CHANNEL_LINK,CHANNEL_COPYRIGHT,\
                         CHANNEL_WEBMASTER,CHANNEL_LANGUAGE,\
                         LAST_BUILD_DATETIME,ORIGIN_DATETIME,\
                         HEADER_XML,CHANNEL_XML,ITEM_XML,BASE_URL,ID \
                         from FEEDS \
                         where KEY_NAME=\"%s\"",getenv("QUERY_STRING"));
  q=new RDSqlQuery(sql);
  if(!q->first()) {
    printf("Content-type: text/html\n\n");
    printf("rdfeed: no feed matches the supplied key name\n");
    db->removeDatabase(config->mysqlDbname());
    exit(0);
  }

  //
  // Generate CGI Header
  //

  printf("Content-type: application/rss+xml\n\n");

  //
  // Render Header XML
  //
  printf("%s\n",(const char *)q->value(9).toString());

  //
  // Render Channel XML
  //
  printf("<channel>\n");
  printf("%s\n",(const char *)ResolveChannelWildcards(q));

  //
  // Render Item XML
  //
  sql=QString().sprintf("select ITEM_TITLE,ITEM_DESCRIPTION,ITEM_CATEGORY,\
                         ITEM_LINK,ITEM_AUTHOR,ITEM_SOURCE_TEXT,\
                         ITEM_SOURCE_URL,ITEM_COMMENTS,\
                         AUDIO_FILENAME,AUDIO_LENGTH,AUDIO_TIME,\
                         ORIGIN_DATETIME,ID from PODCASTS \
                         where (FEED_ID=%d)&&(STATUS=%d) \
                         order by ORIGIN_DATETIME",
			q->value(13).toUInt(),RDPodcast::StatusActive);
  q1=new RDSqlQuery(sql);
  while(q1->next()) {
    printf("<item>\n");
    printf("%s\n",(const char *)ResolveAuxWildcards(ResolveItemWildcards(q1,q),
						    getenv("QUERY_STRING"),
						    q->value(13).toUInt(),
						    q1->value(7).toUInt()));
//    printf("%s\n",(const char *)ResolveItemWildcards(q1,q));
    printf("</item>\n");
  }
  delete q1;

  printf("</channel>\n");
  printf("</rss>\n");
  delete q;

  exit(0);
}


QString MainObject::ResolveChannelWildcards(RDSqlQuery *chan_q)
{
  QString ret=chan_q->value(10).toString();
  ret.replace("%TITLE%",RDEscapeWebString(chan_q->value(0).toString()));
  ret.replace("%DESCRIPTION%",RDEscapeWebString(chan_q->value(1).toString()));
  ret.replace("%CATEGORY%",RDEscapeWebString(chan_q->value(2).toString()));
  ret.replace("%LINK%",RDEscapeWebString(chan_q->value(3).toString()));
  ret.replace("%COPYRIGHT%",RDEscapeWebString(chan_q->value(4).toString()));
  ret.replace("%WEBMASTER%",RDEscapeWebString(chan_q->value(5).toString()));
  ret.replace("%LANGUAGE%",RDEscapeWebString(chan_q->value(6).toString()));
  ret.replace("%BUILD_DATE%",chan_q->value(7).toDateTime().
	      toString("ddd, d MMM yyyy hh:mm:ss ")+
	      RDTimeZoneName(chan_q->value(7).toDateTime()));
  ret.replace("%PUBLISH_DATE%",chan_q->value(8).toDateTime().
	      toString("ddd, d MMM yyyy hh:mm:ss ")+
	      RDTimeZoneName(chan_q->value(8).toDateTime()));
  ret.replace("%GENERATOR%",QString().sprintf("Rivendell %s",VERSION));

  return ret;
}


QString MainObject::ResolveItemWildcards(RDSqlQuery *item_q,RDSqlQuery *chan_q)
{
  QString ret=chan_q->value(11).toString();
  ret.replace("%ITEM_TITLE%",RDEscapeWebString(item_q->value(0).toString()));
  ret.replace("%ITEM_DESCRIPTION%",
	      RDEscapeWebString(item_q->value(1).toString()));
  ret.replace("%ITEM_CATEGORY%",
	      RDEscapeWebString(item_q->value(2).toString()));
  ret.replace("%ITEM_LINK%",RDEscapeWebString(item_q->value(3).toString()));
  ret.replace("%ITEM_AUTHOR%",RDEscapeWebString(item_q->value(4).toString()));
  ret.replace("%ITEM_SOURCE_TEXT%",
	      RDEscapeWebString(item_q->value(5).toString()));
  ret.replace("%ITEM_SOURCE_URL%",
	      RDEscapeWebString(item_q->value(6).toString()));
  ret.replace("%ITEM_COMMENTS%",
	      RDEscapeWebString(item_q->value(7).toString()));
  ret.replace("%ITEM_AUDIO_URL%",
	      QString().sprintf("%s/%s",
				(const char *)chan_q->value(12).toString(),
				(const char *)item_q->value(8).toString()));
  ret.replace("%ITEM_AUDIO_LENGTH%",item_q->value(9).toString());
  ret.replace("%ITEM_AUDIO_TIME%",
	      RDGetTimeLength(item_q->value(10).toInt(),false,false));
  ret.replace("%ITEM_PUBLISH_DATE%",item_q->value(11).toDateTime().
	      toString("ddd, d MMM yyyy hh:mm:ss ")+
	      RDTimeZoneName(item_q->value(10).toDateTime()));
  ret.replace("%ITEM_GUID%",RDPodcast::guid(chan_q->value(12).toString(),
					    item_q->value(8).toString(),
					    chan_q->value(13).toUInt(),
					    item_q->value(12).toUInt()));
  return ret;
}


QString MainObject::ResolveAuxWildcards(QString xml,QString keyname,
					unsigned feed_id,unsigned cast_id)
{
  QString sql;
  RDSqlQuery *q;
  RDSqlQuery *q1;

  keyname.replace(" ","_");
  sql=QString().sprintf("select VAR_NAME from AUX_METADATA where FEED_ID=%u",
			feed_id);
  q=new RDSqlQuery(sql);
  if(q->size()==0) {
    delete q;
    return xml;
  }
  sql="select ";
  while(q->next()) {
    sql+=q->value(0).toString().mid(1,q->value(0).toString().length()-2);
    sql+=",";
  }
  sql=sql.left(sql.length()-1);
  sql+=QString().sprintf(" from %s_FIELDS where CAST_ID=%u",
			 (const char *)keyname,cast_id);
  q->seek(-1);
  q1=new RDSqlQuery(sql);
  while(q1->next()) {
    q->next();
    xml.replace(q->value(0).toString(),
		RDEscapeWebString(q1->value(0).toString()));
  }
  delete q1;
  delete q;

  return xml;
}


int main(int argc,char *argv[])
{
  QApplication a(argc,argv,false);
  new MainObject(NULL,"main");
  return a.exec();
}
